package org.lightrpc.server.http;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.lightrpc.RpcCallParameters;
import org.lightrpc.ServiceNameResolver;
import org.lightrpc.server.ServiceNotFoundException;
import org.lightrpc.server.WebServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpServiceNameResolver implements ServiceNameResolver {
	private static final Logger logger = LoggerFactory
			.getLogger(HttpServiceNameResolver.class);

	@Override
	public Object resolveClass(String serviceName)
			throws ServiceNotFoundException {
		// TODO:i don't think this should be here
		Object service = WebServiceRegistry.findService(serviceName);
		if (service == null)
			throw new ServiceNotFoundException(
					"This service has not been registered to the webservice registry."
							+ "Service name:" + serviceName);
		else
			return service;
	}

	/**
	 * Resolves the type of the parameters from the incoming request. Only
	 * supports Strings & numbers currently (String->String, numbers->Integer)
	 */
	@Override
	public RpcCallParameters resolveClassParameters(List<Object> params,
			Class<?> clazz) {
		// first check by type, (TODO:then by name), There should be a better
		// way of
		// doing this!
		Class<?>[] types = new Class<?>[params.size()];
		// GOtta copy the params to another similar map with correct types
		List<Object> newParamList = new LinkedList<Object>();
		int i = 0;
		for (Object value : params) {
			Object addable;
			try {
				addable = Integer.parseInt((String) value);
				types[i] = Integer.class;
			} catch (NumberFormatException e) {
				types[i] = String.class;
				addable = value;
			}
			newParamList.add(addable);
			i++;
		}
		return new RpcCallParameters(types, newParamList);
	}

	/**
	 * Resolves the remote call string for the method.
	 */
	@Override
	public String resolveRemoteCall(Class<?> iface, Method method, Object[] args) {
		String path = "/" + iface.getSimpleName() + "/" + method.getName();
		if (args != null) {
			path += "?";
			logger.debug("parameter types"
					+ Arrays.asList(method.getParameterTypes()));

			for (int i = 0; i < args.length; i++) {
				try {
					path += i + "="
							+ URLEncoder.encode(args[i].toString(), "UTF-8");
				} catch (UnsupportedEncodingException e) {
					logger.error("The method " + method.getName()
							+ " argument of type " + args[i].getClass()
							+ " could not be encoded", e);
				}
				if (i < args.length - 1)
					path += "&";
			}
		}
		return path;
	}
}